package com.zmn.oms.services.impl.orderencrypt;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.zmn.anole.dubbo.interfaces.AnoleRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.oms.model.entity.ins.*;
import com.zmn.oms.services.interfaces.orderencrypt.InsOrderEncryptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 类描述：
 *
 * @author LiangHailong
 * @date 2021/09/13 17:50
 */
@Slf4j
@Service("insOrderEncryptService")
public class InsOrderEncryptServiceImpl implements InsOrderEncryptService {

    // region 依赖
    @Reference(version = AnoleRemoteService.VERSION, check = false)
    private AnoleRemoteService anoleRemoteService;
    // endregion

    private static final String REG_PHONE_OR_ID = "^[\\d]+[x|X]?$";

    // region InsOrder 加解密
    @Override
    public InsOrder encryptInsOrder(InsOrder insOrder) {
        if (insOrder == null) {
            return insOrder;
        }

        InsOrder insOrderCopy = BeanMapper.map(insOrder, InsOrder.class);
        PhoneAndCardNo phoneAndCardNo = this.encryptPhoneAndCardNo(insOrder.getMasterPhone(), insOrder.getMasterCardNo());
        insOrderCopy.setMasterPhone(phoneAndCardNo.phone);
        insOrderCopy.setMasterCardNo(phoneAndCardNo.cardNo);

        return insOrderCopy;
    }

    public static void main(String[] args) {
        String phone = "18010491280";
        String cardNo = "11010020001012785X";

        System.out.println("phone="+ String.valueOf(Pattern.matches(REG_PHONE_OR_ID, phone)));
        System.out.println("cardNo="+ String.valueOf(Pattern.matches(REG_PHONE_OR_ID, cardNo)));
    }


    @Override
    public InsOrder decryptInsOrder(InsOrder insOrder) {
        if (insOrder == null) {
            return insOrder;
        }

        InsOrder insOrderCopy = BeanMapper.map(insOrder, InsOrder.class);
        PhoneAndCardNo phoneAndCardNo = this.decryptPhoneAndCardNo(insOrder.getMasterPhone(), insOrder.getMasterCardNo());
        insOrderCopy.setMasterPhone(phoneAndCardNo.phone);
        insOrderCopy.setMasterCardNo(phoneAndCardNo.cardNo);

        return insOrder;
    }

    @Override
    public List<InsOrder> batchDecryptInsOrder(List<InsOrder> insOrders) {
        if (insOrders == null || insOrders.isEmpty()) {
            return insOrders;
        }

        final List<InsOrder> insOrdersCopy = BeanMapper.mapList(insOrders, InsOrder.class);

        // 提取需要解密的手机号和身份证号
        Map<String, String> phoneMap = new HashMap<>(insOrdersCopy.size());
        Map<String, String> cardNoMap = new HashMap<>(insOrdersCopy.size());
        for (int i=0,len=insOrdersCopy.size(); i<len; i++) {
            InsOrder item = insOrdersCopy.get(i);

            if (StringUtil.isNotBlank(item.getMasterPhone())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterPhone())) {
                phoneMap.put(String.valueOf(i), item.getMasterPhone());
            }
            if (StringUtil.isNotBlank(item.getMasterCardNo())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterCardNo())) {
                cardNoMap.put(String.valueOf(i), item.getMasterCardNo());
            }
        }

        // 解密手机号
        if (!phoneMap.isEmpty()) {
            Map<String, String> decryptPhones = this.decryptMulti(phoneMap);
            if (decryptPhones != null) {
                decryptPhones.forEach((key, value) -> {
                    InsOrder insOrder = insOrdersCopy.get(Integer.parseInt(key));
                    if (insOrder != null && StringUtil.isNotBlank(value)) {
                        insOrder.setMasterPhone(value);
                    }
                });
            }
        }

        // 解密身份证号
        if (!cardNoMap.isEmpty()) {
            Map<String, String> decryptCardNos = this.decryptMulti(cardNoMap);
            if (decryptCardNos != null) {
                decryptCardNos.forEach((key, value) -> {
                    InsOrder insOrder = insOrdersCopy.get(Integer.parseInt(key));
                    if (insOrder != null && StringUtil.isNotBlank(value)) {
                        insOrder.setMasterCardNo(value);
                    }
                });
            }
        }

        return insOrdersCopy;
    }
    // endregion

    // region InsOrderMaster 加解密
    @Override
    public InsOrderMaster encryptInsOrderMaster(InsOrderMaster insOrderMaster) {
        if (insOrderMaster == null) {
            return insOrderMaster;
        }

        InsOrderMaster insOrderMasterCopy = BeanMapper.map(insOrderMaster, InsOrderMaster.class);
        PhoneAndCardNo phoneAndCardNo = this.encryptPhoneAndCardNo(
                insOrderMaster.getMasterPhone(), insOrderMaster.getMasterCardNo()
        );
        insOrderMasterCopy.setMasterPhone(phoneAndCardNo.phone);
        insOrderMasterCopy.setMasterCardNo(phoneAndCardNo.cardNo);

        return insOrderMasterCopy;
    }

    @Override
    public List<InsOrderMaster> batchDecryptInsOrderMaster(List<InsOrderMaster> insOrderMasters) {
        if (insOrderMasters == null || insOrderMasters.isEmpty()) {
            return insOrderMasters;
        }

        final List<InsOrderMaster> insOrderMastersCopy = BeanMapper.mapList(insOrderMasters, InsOrderMaster.class);

        // 提取需要解密的手机号和身份证号
        Map<String, String> phoneMap = new HashMap<>(insOrderMasters.size());
        Map<String, String> cardNoMap = new HashMap<>(insOrderMasters.size());
        for (int i=0,len=insOrderMastersCopy.size(); i<len; i++) {
            InsOrderMaster item = insOrderMastersCopy.get(i);

            if (StringUtil.isNotBlank(item.getMasterPhone())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterPhone())) {
                phoneMap.put(String.valueOf(i), item.getMasterPhone());
            }
            if (StringUtil.isNotBlank(item.getMasterCardNo())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterCardNo())) {
                cardNoMap.put(String.valueOf(i), item.getMasterCardNo());
            }
        }

        // 解密手机号
        if (!phoneMap.isEmpty()) {
            Map<String, String> decryptPhones = this.decryptMulti(phoneMap);
            if (decryptPhones != null) {
                decryptPhones.forEach((key, value) -> {
                    InsOrderMaster insOrderMaster = insOrderMastersCopy.get(Integer.parseInt(key));
                    if (insOrderMaster != null && StringUtil.isNotBlank(value)) {
                        insOrderMaster.setMasterPhone(value);
                    }
                });
            }
        }

        // 解密身份证号
        if (!cardNoMap.isEmpty()) {
            Map<String, String> decryptCardNos = this.decryptMulti(cardNoMap);
            if (decryptCardNos != null) {
                decryptCardNos.forEach((key, value) -> {
                    InsOrderMaster insOrderMaster = insOrderMastersCopy.get(Integer.parseInt(key));
                    if (insOrderMaster != null && StringUtil.isNotBlank(value)) {
                        insOrderMaster.setMasterCardNo(value);
                    }
                });
            }
        }

        return insOrderMastersCopy;
    }
    // endregion

    // region InsOrderMaster 加解密
    @Override
    public InsOrderSync encryptInsOrderSync(InsOrderSync insOrderSync) {
        if (insOrderSync == null) {
            return insOrderSync;
        }

        InsOrderSync insOrderSyncCopy = BeanMapper.map(insOrderSync, InsOrderSync.class);
        PhoneAndCardNo phoneAndCardNo = this.encryptPhoneAndCardNo(null, insOrderSync.getServicemanCardNo());
        insOrderSyncCopy.setServicemanCardNo(phoneAndCardNo.cardNo);

        return insOrderSyncCopy;
    }

    @Override
    public List<InsOrderSync> batchEncryptInsOrderSync(List<InsOrderSync> insOrderSyncs) {
        if (insOrderSyncs == null || insOrderSyncs.isEmpty()) {
            return insOrderSyncs;
        }

        final List<InsOrderSync> insOrderSyncsCopy = BeanMapper.mapList(insOrderSyncs, InsOrderSync.class);

        // 提取需要加密的身份证号
        Map<String, String> cardNoMap = new HashMap<>(insOrderSyncsCopy.size());
        for (int i=0,len=insOrderSyncsCopy.size(); i<len; i++) {
            InsOrderSync item = insOrderSyncsCopy.get(i);
            if (StringUtil.isNotBlank(item.getServicemanCardNo())
                    && Pattern.matches(REG_PHONE_OR_ID, item.getServicemanCardNo())) {
                cardNoMap.put(String.valueOf(i), item.getServicemanCardNo());
            }
        }
        // 加密身份证号
        if (!cardNoMap.isEmpty()) {
            Map<String, String> decryptCardNos = this.encryptMulti(cardNoMap);
            if (decryptCardNos != null) {
                decryptCardNos.forEach((key, value) -> {
                    InsOrderSync insOrderSync = insOrderSyncsCopy.get(Integer.parseInt(key));
                    if (insOrderSync != null && StringUtil.isNotBlank(value)) {
                        insOrderSync.setServicemanCardNo(value);
                    }
                });
            }
        }

        return insOrderSyncsCopy;
    }

    @Override
    public List<InsOrderSync> batchDecryptInsOrderSync(List<InsOrderSync> insOrderSyncs) {
        if (insOrderSyncs == null || insOrderSyncs.isEmpty()) {
            return insOrderSyncs;
        }

        final List<InsOrderSync> insOrderSyncsCopy = BeanMapper.mapList(insOrderSyncs, InsOrderSync.class);

        // 提取需要解密的身份证号
        Map<String, String> cardNoMap = new HashMap<>(insOrderSyncsCopy.size());
        for (int i=0,len=insOrderSyncsCopy.size(); i<len; i++) {
            InsOrderSync item = insOrderSyncsCopy.get(i);
            if (StringUtil.isNotBlank(item.getServicemanCardNo())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getServicemanCardNo())) {
                cardNoMap.put(String.valueOf(i), item.getServicemanCardNo());
            }
        }
        // 解密身份证号
        if (!cardNoMap.isEmpty()) {
            Map<String, String> decryptCardNos = this.decryptMulti(cardNoMap);
            if (decryptCardNos != null) {
                decryptCardNos.forEach((key, value) -> {
                    InsOrderSync insOrderSync = insOrderSyncsCopy.get(Integer.parseInt(key));
                    if (insOrderSync != null && StringUtil.isNotBlank(value)) {
                        insOrderSync.setServicemanCardNo(value);
                    }
                });
            }
        }

        return insOrderSyncsCopy;
    }
    // endregion

    // region InsOrderMasterCpic 加解密
    @Override
    public InsOrderMasterCpic encryptInsOrderMasterCpic(InsOrderMasterCpic insOrderMasterCpic) {
        if (insOrderMasterCpic == null) {
            return insOrderMasterCpic;
        }

        InsOrderMasterCpic insOrderMasterCpicCopy = BeanMapper.map(insOrderMasterCpic, InsOrderMasterCpic.class);
        PhoneAndCardNo phoneAndCardNo = this.encryptPhoneAndCardNo(
                insOrderMasterCpic.getMasterPhone(), insOrderMasterCpic.getMasterCardNo()
        );
        insOrderMasterCpicCopy.setMasterPhone(phoneAndCardNo.phone);
        insOrderMasterCpicCopy.setMasterCardNo(phoneAndCardNo.cardNo);

        return insOrderMasterCpicCopy;
    }

    @Override
    public List<InsOrderMasterCpic> batchDecryptInsOrderMasterCpic(List<InsOrderMasterCpic> insOrderMasterCpics) {
        if (insOrderMasterCpics == null || insOrderMasterCpics.isEmpty()) {
            return insOrderMasterCpics;
        }

        final List<InsOrderMasterCpic> insOrderMasterCpicsCopy = BeanMapper.mapList(insOrderMasterCpics, InsOrderMasterCpic.class);

        // 提取需要解密的手机号和身份证号
        Map<String, String> phoneMap = new HashMap<>(insOrderMasterCpics.size());
        Map<String, String> cardNoMap = new HashMap<>(insOrderMasterCpics.size());
        for (int i=0,len=insOrderMasterCpicsCopy.size(); i<len; i++) {
            InsOrderMasterCpic item = insOrderMasterCpicsCopy.get(i);

            if (StringUtil.isNotBlank(item.getMasterPhone())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterPhone())) {
                phoneMap.put(String.valueOf(i), item.getMasterPhone());
            }
            if (StringUtil.isNotBlank(item.getMasterCardNo())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterCardNo())) {
                cardNoMap.put(String.valueOf(i), item.getMasterCardNo());
            }
        }

        // 解密手机号
        if (!phoneMap.isEmpty()) {
            Map<String, String> decryptPhones = this.decryptMulti(phoneMap);
            if (decryptPhones != null) {
                decryptPhones.forEach((key, value) -> {
                    InsOrderMasterCpic insOrderMasterCpic = insOrderMasterCpicsCopy.get(Integer.parseInt(key));
                    if (insOrderMasterCpic != null && StringUtil.isNotBlank(value)) {
                        insOrderMasterCpic.setMasterPhone(value);
                    }
                });
            }
        }

        // 解密身份证号
        if (!cardNoMap.isEmpty()) {
            Map<String, String> decryptCardNos = this.decryptMulti(cardNoMap);
            if (decryptCardNos != null) {
                decryptCardNos.forEach((key, value) -> {
                    InsOrderMasterCpic insOrderMasterCpic = insOrderMasterCpicsCopy.get(Integer.parseInt(key));
                    if (insOrderMasterCpic != null && StringUtil.isNotBlank(value)) {
                        insOrderMasterCpic.setMasterCardNo(value);
                    }
                });
            }
        }

        return insOrderMasterCpicsCopy;
    }
    // endregion

    // region InsOrderMasterSync 加解密
    @Override
    public InsOrderMasterSync encryptInsOrderMasterSync(InsOrderMasterSync insOrderMasterSync) {
        if (insOrderMasterSync == null) {
            return insOrderMasterSync;
        }

        InsOrderMasterSync insOrderMasterSyncCopy = BeanMapper.map(insOrderMasterSync, InsOrderMasterSync.class);
        PhoneAndCardNo phoneAndCardNo = this.encryptPhoneAndCardNo(insOrderMasterSync.getMasterMoblie(), null);
        insOrderMasterSyncCopy.setMasterMoblie(phoneAndCardNo.phone);

        return insOrderMasterSyncCopy;
    }

    @Override
    public List<InsOrderMasterSync> batchDecryptInsOrderMasterSync(List<InsOrderMasterSync> insOrderMasterSyncs) {
        if (insOrderMasterSyncs == null || insOrderMasterSyncs.isEmpty()) {
            return insOrderMasterSyncs;
        }

        final List<InsOrderMasterSync> insOrderMasterSyncsCopy = BeanMapper.mapList(insOrderMasterSyncs, InsOrderMasterSync.class);

        // 提取需要解密的手机号
        Map<String, String> phoneMap = new HashMap<>(insOrderMasterSyncs.size());
        for (int i=0,len=insOrderMasterSyncsCopy.size(); i<len; i++) {
            InsOrderMasterSync item = insOrderMasterSyncsCopy.get(i);

            if (StringUtil.isNotBlank(item.getMasterMoblie())
                    && !Pattern.matches(REG_PHONE_OR_ID, item.getMasterMoblie())) {
                phoneMap.put(String.valueOf(i), item.getMasterMoblie());
            }
        }

        // 解密手机号
        if (!phoneMap.isEmpty()) {
            Map<String, String> decryptPhones = this.decryptMulti(phoneMap);
            if (decryptPhones != null) {
                decryptPhones.forEach((key, value) -> {
                    InsOrderMasterSync insOrderMasterSync = insOrderMasterSyncsCopy.get(Integer.parseInt(key));
                    if (insOrderMasterSync != null && StringUtil.isNotBlank(value)) {
                        insOrderMasterSync.setMasterMoblie(value);
                    }
                });
            }
        }

        return insOrderMasterSyncsCopy;
    }
    // endregion

    // region Private Method
    private PhoneAndCardNo encryptPhoneAndCardNo(String phone, String cardNo) {
        final PhoneAndCardNo phoneAndCardNo = new PhoneAndCardNo(phone, cardNo);

        boolean phoneNeedEncrypt = StringUtil.isNotBlank(phone)
                && Pattern.matches(REG_PHONE_OR_ID, phone);
        boolean cardNoNeedEncrypt = StringUtil.isNotBlank(cardNo)
                && Pattern.matches(REG_PHONE_OR_ID, cardNo);

        String encryptedPhone = null;
        String encryptedCardNo = null;

        // 电话和身份证号都需要加密的话，合并成一次加密请求
        if (phoneNeedEncrypt && cardNoNeedEncrypt) {
            Map<String, String> map = new HashMap<>(2);
            map.put("phone", phone);
            map.put("cardNo", cardNo);

            Map<String, String> encryptMulti = this.encryptMulti(map);
            encryptedPhone = encryptMulti.get("phone");
            encryptedCardNo = encryptMulti.get("cardNo");
        }
        else {
            if (phoneNeedEncrypt) {
                encryptedPhone = this.encryptOne(phone);
            }
            if (cardNoNeedEncrypt) {
                encryptedCardNo = this.encryptOne(cardNo);
            }
        }

        if (phoneNeedEncrypt && StringUtil.isNotBlank(encryptedPhone)) {
            phoneAndCardNo.phone = encryptedPhone;
        }
        if (cardNoNeedEncrypt && StringUtil.isNotBlank(encryptedCardNo)) {
            phoneAndCardNo.cardNo = encryptedCardNo;
        }

        return phoneAndCardNo;
    }
    private PhoneAndCardNo decryptPhoneAndCardNo(String phone, String cardNo) {
        final PhoneAndCardNo phoneAndCardNo = new PhoneAndCardNo(phone, cardNo);

        boolean phoneNeedDecrypt = StringUtil.isNotBlank(phone)
                && !Pattern.matches(REG_PHONE_OR_ID, phone);
        boolean cardNoNeedDecrypt = StringUtil.isNotBlank(cardNo)
                && !Pattern.matches(REG_PHONE_OR_ID, cardNo);

        String decryptedPhone = null;
        String decryptedCardNo = null;
        // 电话和身份证号都需要加密的话，合并成一次加密请求
        if (phoneNeedDecrypt && cardNoNeedDecrypt) {
            Map<String, String> map = new HashMap<>(2);
            map.put("phone", phone);
            map.put("cardNo", cardNo);

            Map<String, String> encryptMulti = this.decryptMulti(map);
            decryptedPhone = encryptMulti.get("phone");
            decryptedCardNo = encryptMulti.get("cardNo");
        }
        else {
            if (phoneNeedDecrypt) {
                decryptedPhone = this.decryptOne(phone);
            }
            if (cardNoNeedDecrypt) {
                decryptedCardNo = this.encryptOne(cardNo);
            }
        }

        if (phoneNeedDecrypt && StringUtil.isNotBlank(decryptedPhone)) {
            phoneAndCardNo.phone = decryptedPhone;
        }
        if (cardNoNeedDecrypt && StringUtil.isNotBlank(decryptedCardNo)) {
            phoneAndCardNo.cardNo = decryptedCardNo;
        }
        return phoneAndCardNo;
    }
    private String encryptOne(String str) {
        ResponseDTO<String> encryptRemote = anoleRemoteService.encrypt(str);
        log.debug("anoleRemoteService#encrypt 入参[{}],出参[{}]", str, encryptRemote.getData());
        if (encryptRemote.isSuccess()) {
            return encryptRemote.getData();
        } else {
            log.error("入参[{}],加密失败[{}]", str, encryptRemote.getMessage());
            return null;
        }
    }
    private String decryptOne(String str) {
        ResponseDTO<String> encryptRemote = anoleRemoteService.decrypt(str);
        log.debug("anoleRemoteService#encrypt 入参[{}],出参[{}]", str, encryptRemote.getData());
        if (encryptRemote.isSuccess()) {
            return encryptRemote.getData();
        } else {
            log.error("入参[{}],加密失败[{}]", str, encryptRemote.getMessage());
            return null;
        }
    }
    private Map<String, String> encryptMulti(Map<String, String> map) {
        ResponseDTO<Map<String, String>> encryptRemote = anoleRemoteService.batchEncryptMap(map);
        log.debug("anoleRemoteService#batchEncryptMap 入参[{}],出参[{}]",
                JSON.toJSONString(map), JSON.toJSONString(encryptRemote.getData())
        );
        if (encryptRemote.isSuccess()) {
            return encryptRemote.getData();
        } else {
            log.error("入参[{}],加密失败[{}]", JSON.toJSONString(map), encryptRemote.getMessage());
            return null;
        }
    }
    private Map<String, String> decryptMulti(Map<String, String> map) {
        ResponseDTO<Map<String, String>> encryptRemote = anoleRemoteService.batchDecryptMap(map);
        log.debug("anoleRemoteService#batchEncryptMap 入参[{}],出参[{}]",
                JSON.toJSONString(map), JSON.toJSONString(encryptRemote.getData())
        );
        if (encryptRemote.isSuccess()) {
            return encryptRemote.getData();
        } else {
            log.error("入参[{}],加密失败[{}]", JSON.toJSONString(map), encryptRemote.getMessage());
            return null;
        }
    }
    // endregion

    // region
    private static class PhoneAndCardNo {
        private String phone;
        private String cardNo;

        private PhoneAndCardNo(String phone, String cardNo) {
            this.phone = phone;
            this.cardNo = cardNo;
        }
    }
    // endregion
}
